/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.gebze.Util;

import java.io.*;
import org.gebze.param.Parametre;

/**
 * Server tarafından her client için dinleme clası
 *
 * @author Özcan ÇAĞIRICI <ozcan.cagirici@gmail.com>
 *
 * @author Hatice Şahin <haticesahin.09@gmail.com>
 */
public class GbzScannerClientHandler extends Thread {

    private BufferedReader in;
    private InputStream ins;
    private OutputStreamWriter out;
    private OutputStream outs;
    private transient boolean connected = true;
    private boolean isConnected;

    public GbzScannerClientHandler(InputStream ins, OutputStream outs) {
        this.ins = ins;
        this.outs = outs;
        Reader isread = new InputStreamReader(ins);
        in = new BufferedReader(isread);
        out = new OutputStreamWriter(outs);
        isConnected = true;
    }

    @Override
    public void run() {
       
        while (isConnected) {
            //bir değişken yardımıyla, mmesaj gönderilip
            //gönderilmeyeceği kontrol edilecek. ve client ile mesajlaşacak.
            
            
            
        }
    }

    
    /**
     * "Clienttan data oku" komutunu karşılar
     * @return 
     */
    public byte[] getClientScanData() {
        sendMessage("P"); //öncelikle tara komutunu gondeririz clienta
        byte[] kaynakByte = null;
        kaynakByte = getImageFromClient();
        if (kaynakByte != null) {
            String mesaj = (kaynakByte.length + " uzunlugunda dosya alindi");
            sendMessage(mesaj);

        } else {
            String mesaj = ("dosya alinamadi");
            sendMessage(mesaj);
        }
        return kaynakByte;
    }

    
    /**
     * Clienttan gelen parcalanmış datayı okur ve header
     * numarasına gore birleştirir.
     * @return 
     */
    private byte[] getImageFromClient() {
        byte[] originalData = null;
        int gelecekDosyaBoyutu = 0, tekrarSayisi = 0, artanMiktar = 0;

        try {
            gelecekDosyaBoyutu = ins.read();
        } catch (IOException ex) {
            System.out.println("Clienttan veriler okunamadi. ");
            return originalData;
        }

        tekrarSayisi = gelecekDosyaBoyutu / Parametre.MAX_DATA_PARCA_BOYUTU;
        artanMiktar = gelecekDosyaBoyutu % Parametre.MAX_DATA_PARCA_BOYUTU;
        originalData = new byte[gelecekDosyaBoyutu];
        for (int i = 0; i < tekrarSayisi; i++) {
            originalData = parcaOkuBirlestir(originalData, Parametre.MAX_PARCA_BOYUTU);
        }
        if (artanMiktar != 0) {
            originalData = parcaOkuBirlestir(originalData, artanMiktar + Parametre.PARCA_HEADER_SIZE);
        }
     
        return originalData;
    }

    /**
     * gelen byte dizisine ait header bilgisini cikararak orjinal veri dizisini
     * dondurur.
     *
     * @param okunanParca
     * @return
     */
    private byte[] getOriginalParca(byte[] okunanParca) {
        byte[] retValue = null;

        retValue = new byte[okunanParca.length - Parametre.PARCA_HEADER_SIZE];
        int baslangic_degeri = 0;
        for (int i = Parametre.PARCA_HEADER_SIZE; i < okunanParca.length; i++) {
            retValue[baslangic_degeri++] = okunanParca[i];
        }
        return retValue;
    }

    /**
     *
     * Kaynak dizinin elemanlarını, verilen parca sirasina gore hedef arraye
     * atar.
     *
     * @param hedefArray
     * @param kaynakArray
     * @param parcaSirasi
     * @return
     */
    private byte[] setParcaBirlestir(byte[] hedefArray, byte[] kaynakArray, int parcaSirasi) {
        int index = parcaSirasi * Parametre.MAX_DATA_PARCA_BOYUTU;
        for (int j = 0; j < kaynakArray.length; ++j) {
            hedefArray[index++] = kaynakArray[j];
        }
        return hedefArray;
    }

    /**
     * Inputstreamden lenght kadar veriyi okur, header bilgisni çıkarıp olusan
     * veriyi, parametre olarak gelen diziye ekler
     *
     *
     * @param originalData
     * @param length
     * @return
     */
    private byte[] parcaOkuBirlestir(byte[] originalData, int length) {
        byte[] okunanParca = new byte[length];
        byte[] originalParca = new byte[length - Parametre.PARCA_HEADER_SIZE];
        try {
            ins.read(okunanParca);

        } catch (IOException ex) {
            System.out.println("Parca okunamadi.");
        }
        int headerNo = Convert32BitsToInt(okunanParca, 0);
        originalParca = getOriginalParca(okunanParca);
        originalData = setParcaBirlestir(originalData, originalParca, headerNo);
        return originalData;

    }

    /**
     * Verilen byte dizisine ait header bilgisini okuyarak, headerı geri
     * dondurur.
     *
     * @param b
     * @param offset
     * @return
     */
    private int Convert32BitsToInt(byte[] b, int offset) {
        int value = 0;
        for (int i = 0; i < 4; i++) {
            int k = (4 - 1 - i) * 8;
            value += (b[i + offset] & 0x000000FF) << k;
        }
        return value;
    }

    /**
     * client tarafından gelen mesajların okundugu method
     *
     * @return
     */
    public String getClientMessage() {
        String clientMesaji = null;
        try {
            clientMesaji = in.readLine();
        } catch (IOException ex) {
            System.out.println("Mesaj okunurken hata olustu: " + ex);
        }

        return clientMesaji;
    }

    /**
     * serverin istegini(mesajını) clienta gonderir.
     *
     * @param serverMesaj
     */
    public void sendMessage(String serverMesaj) {

        try {
            out.write(serverMesaj + "\n");
            out.flush();
        } catch (IOException ex) {
            System.out.println("Mesaj gonderilemedi.. ");
        }
    }

   /* public BufferedReader getIn() {
        return in;
    }

    public void setIn(BufferedReader in) {
        this.in = in;
    }

    public OutputStreamWriter getOut() {
        return out;
    }

    public void setOut(OutputStreamWriter out) {
        this.out = out;
    }

    public InputStream getIns() {
        return ins;
    }

    public void setIns(InputStream ins) {
        this.ins = ins;
    }

    public OutputStream getOuts() {
        return outs;
    }

    public void setOuts(OutputStream outs) {
        this.outs = outs;
    }

    public boolean isConnected() {
        return connected;
    }

    public void setConnected(boolean connected) {
        this.connected = connected;
    }*/
}